#include "my_storage_manager.h"
#include "my_nvs.hpp"
#include <bit>
#include <string.h>


#define TAG "StorageManager"

#define BITMAP_KEY          (prefix_ + std::string(CONFIG_BITMAP_KEY))
#define FIELD_COUNT_KEY     (prefix_ + std::string(CONFIG_FIELD_COUNT_KEY))
#define TOTAL_BYTES_KEY     (prefix_ + std::string(CONFIG_TOTAL_BYTES_KEY))
#define FIELD_TYPE_KEY      (prefix_ + std::string(CONFIG_FIELD_TYPE_KEY))
#define FIELD_BYTES_KEY     (prefix_ + std::string(CONFIG_FIELD_BYTES_KEY))
#define FIELD_OFFSET_KEY    (prefix_ + std::string(CONFIG_FIELD_OFFSET_KEY))

StorageManager::StorageManager(const std::string& nspace, const std::string& prefix, const StructMeta& meta)
    : nvs_(nspace.c_str(), NVS_READWRITE)
    , used_(0)
    , space_(CONFIG_MAX_STORAGE)
    , prefix_(prefix)
    , bitmap_(0)
    , meta_(meta)
{


    auto err = nvs_.read(BITMAP_KEY, bitmap_);
    if (ESP_ERR_NVS_NOT_FOUND == err) {
        if (ESP_OK != Format(nspace, prefix_, meta_)) {
            ESP_LOGE(TAG, "Detect unformat nvs, format failed.");
            return;
        }
    } else if (ESP_OK != err) {
        ESP_LOGE(TAG, "Load bit map failed, nvs_ err:%s", esp_err_to_name(err));
        return;
    } else {
        // 检查元信息
        StructMeta nvs_meta;

        // 检查字段数量
        auto key = FIELD_COUNT_KEY;
        auto err = nvs_.read(key, nvs_meta.field_count);
        if (ESP_OK != err) {
            ESP_LOGE(TAG, "Read meta field length failed.");
            return;
        }
        if (nvs_meta.field_count != meta_.field_count) {
            ESP_LOGW(TAG, "Format nvs.");
            Format(nspace, prefix_, meta_);
            return;
        }

        // 检查字节数量
        key = TOTAL_BYTES_KEY;
        err = nvs_.read(key, nvs_meta.total_bytes);
        if (ESP_OK != err) {
            ESP_LOGE(TAG, "Read meta field bytes failed.");
            Format(nspace, prefix_, meta_);
            return;
        }
        if (nvs_meta.total_bytes != meta_.total_bytes) {
            ESP_LOGW(TAG, "Format nvs.");
            Format(nspace, prefix_, meta_);
            return;
        }
        // 检查各字段
        auto type_pre = FIELD_TYPE_KEY;
        auto byte_pre = FIELD_BYTES_KEY;
        auto offset_pre = FIELD_OFFSET_KEY;
        FieldType type = kUnsupport;
        FieldBytes bytes = 0;
        size_t offset = 0;
        for (auto i = 0; i < meta_.field_count; i++) {
            // 类型检查
            key = type_pre + std::to_string(i);
            err = nvs_.read(key, type);
            if (ESP_OK != err) {
                ESP_LOGE(TAG, "Read meta field %d failed, err=%s", i, esp_err_to_name(err));
                return;
            } 
            if (type != meta_.data[i].type) {
                ESP_LOGW(TAG, "Field %d is not valid.", i);
                Format(nspace, prefix_, meta_);
                return;
            }

            // 字节检查
            key = byte_pre + std::to_string(i);
            err = nvs_.read(key, bytes);
            if (ESP_OK != err) {
                ESP_LOGE(TAG, "Read meta field %d failed, err=%s", i, esp_err_to_name(err));
                return;
            } 
            if (bytes != meta_.data[i].bytes) {
                ESP_LOGW(TAG, "Field %d is not valid.", i);
                Format(nspace, prefix_, meta_);
                return;
            }

            // 偏移检查
            key = offset_pre + std::to_string(i);
            err = nvs_.read(key, offset);
            if (ESP_OK != err) {
                ESP_LOGE(TAG, "Read meta field %d failed, err=%s", i, esp_err_to_name(err));
                return;
            } 
            if (offset != meta_.data[i].offset) {
                ESP_LOGW(TAG, "Field %d is not valid.", i);
                Format(nspace, prefix_, meta_);
                return;
            }
        }
        used_ = std::popcount(bitmap_);
    }
    ESP_LOGI(TAG, "NVS meta check/init ok, bitmap_=%02xH, used/space=%d/%d", bitmap_, used_, space_);
}

StorageManager::~StorageManager()
{
    nvs_.commit();
}

/// @brief 获取存储第1个数据的索引
/// @return 返回第1个数据索引，无数据时返回 CONFIG_MAX_STORAGE
BitmapIndex StorageManager::begin() const
{
    if (!bitmap_) {
        return CONFIG_MAX_STORAGE;
    } 
    
    return std::countr_zero(bitmap_);
}

/// @brief 获取存储最后1个数据的索引的下一位
/// @return 返回的索引是最后一位有效索引后的第1个无效索引
BitmapIndex StorageManager::end() const
{
    if (!bitmap_) {
        return 0;
    }

    return (sizeof(bitmap_) << 3) - std::countl_zero(bitmap_);
}

BitmapIndex StorageManager::next(const BitmapIndex i) const 
{
    constexpr BitmapIndex max_index = sizeof(bitmap_) << 3;

    if (i >= max_index - 1 || bitmap_ == 0) {
        return max_index;
    }

    for (auto index = i + 1; index < max_index; index++) {
        if (bitmap_ & (BitmapType(1) << index)) {
            return index;
        }
    }
    
    return max_index;
}


/// @brief 格式化NVS
/// @param nspace 结构存储使用的名字空间 
/// @param prefix 键前缀（区分相同名字空间的不同结构）
/// @param meta 结构存储元数据
/// @return 
esp_err_t StorageManager::Format(const std::string& nspace,
                                        const std::string&prefix, 
                                        const StructMeta& meta)
{
    MyNVS nvs(nspace.c_str(), NVS_READWRITE);
    
    // 格式化位图
    auto key = prefix + CONFIG_BITMAP_KEY;
    auto err = nvs.write(key, 0);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Formatting storage failed, err=%s", esp_err_to_name(err));
        return err;
    }

    // 写入元数据：字段数量
    key = prefix + CONFIG_FIELD_COUNT_KEY;
    err = nvs.write(key, meta.field_count);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Write meta length failed, err=%s", esp_err_to_name(err));
        return err;
    }
    // 写入元数据：总字节数
    key = prefix + CONFIG_TOTAL_BYTES_KEY;
    err = nvs.write(key, meta.total_bytes);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Write meta bytes failed, err=%s", esp_err_to_name(err));
        return err;
    }

    auto type_pre = prefix + CONFIG_FIELD_TYPE_KEY;
    auto byte_pre = prefix + CONFIG_FIELD_BYTES_KEY;
    auto offset_pre = prefix + CONFIG_FIELD_OFFSET_KEY;
    for (auto i = 0; i < meta.field_count; i++) {
        // 写入字段类型
        key = type_pre + std::to_string(i);
        err = nvs.write(key, meta.data[i].type);
        if (ESP_OK != err) {
            ESP_LOGE(TAG, "Write field %d type failed, err=%s", i, esp_err_to_name(err));
            return err;
        }

        // 写入字段字节
        key = byte_pre + std::to_string(i);
        err = nvs.write(key, meta.data[i].bytes);
        if (ESP_OK != err) {
            ESP_LOGE(TAG, "Write field %d bytes failed, err=%s", i, esp_err_to_name(err));
            return err;
        }

        // 写入字段偏移
        key = offset_pre + std::to_string(i);
        err = nvs.write(key, meta.data[i].offset);
        if (ESP_OK != err) {
            ESP_LOGE(TAG, "Write field %d offset failed, err=%s", i, esp_err_to_name(err));
            return err;
        }
    }
    return err;
}

/// @brief 清空存储
/// @return 返回位图写入结果
esp_err_t StorageManager::Clear()
{
    // nvs_实例要commit
    bitmap_ = 0;
    auto key = BITMAP_KEY;
    auto err = nvs_.write(key, bitmap_);
    if (ESP_OK != err) {
        ESP_LOGE(TAG, "Clear bitmap failed.");
        return err;
    }
    used_ = 0;
    nvs_.commit();

    return ESP_OK;
}

/// @brief 获取1个空闲的存储位置
/// @return 存储已满时返回最大的值
BitmapIndex StorageManager::GetFreeIndex()
{
    if (bitmap_ == ~BitmapType(0)) {
        return CONFIG_MAX_STORAGE;
    }

    return std::countr_zero(~bitmap_);
}

/// @brief 读取一个字段
/// @param key 键名
/// @param field_type 字段类型
/// @param data 字段数据
/// @return 读取结果
esp_err_t StorageManager::ReadField(const std::string& key, FieldType field_type, void* data, FieldBytes bytes)
{
    switch (field_type) {
      case kNormal_1:
        return nvs_.read(key, *static_cast<uint8_t*>(data));
      case kNormal_2:
        return nvs_.read(key, *static_cast<uint16_t*>(data));
      case kNormal_4:
        return nvs_.read(key, *static_cast<uint32_t*>(data));
      case kNormal_8:
        return nvs_.read(key, *static_cast<uint64_t*>(data));
      case kString:
        {
            std::string tmp;
            auto err = nvs_.read(key, tmp);
            if (err == ESP_OK) {
                *reinterpret_cast<std::string*>(data) = std::move(tmp);
            }
            return err;
        //   std::string* str = new (data) std::string();
        //   return nvs_.read(key, *reinterpret_cast<std::string*>(data));
        }
      case kArray_Char:
        return nvs_.read(key, static_cast<char *>(data));   // 需确定是否支持
      case kArray_Blob:
        {
            if (bytes == 0) {
            ESP_LOGE(TAG, "Invalid used of this api, bytes=0 when read blob.");
            return ESP_FAIL;
            }
            size_t read_bytes = 0;
            auto err = nvs_.read(key, data, &read_bytes);
            if (read_bytes == bytes) {
                return err;
            }
            ESP_LOGE(TAG, "Read blob bytes not equal given bytes.");
            return ESP_FAIL;
        }
      default:
        ESP_LOGE(TAG, "Un support type.");
        return ESP_ERR_NOT_SUPPORTED;
    }
}

/// @brief 根据条件决定是否比较写入一个字段
/// @param key 键名
/// @param field_type 字段类型
/// @param ndptr 新原数据
/// @param odptr 旧数据指针，为空时不比较
/// @return 
esp_err_t StorageManager::WriteField(const std::string& key, FieldType field_type, const void* data, FieldBytes bytes)
{
    switch (field_type) {
      case kNormal_1:
        return nvs_.write(key, *static_cast<const uint8_t*>(data));
      case kNormal_2:
        return nvs_.write(key, *static_cast<const uint16_t*>(data));
      case kNormal_4:
        return nvs_.write(key, *static_cast<const uint32_t*>(data));
      case kNormal_8:
        return nvs_.write(key, *static_cast<const uint64_t*>(data));
      case kString:
        return nvs_.write(key, *static_cast<const std::string*>(data));
      case kArray_Char:
        return nvs_.write(key, static_cast<const char*>(data));
      case kArray_Blob:
        if (bytes <= 0) {
            ESP_LOGE(TAG, "Invalid arg: bytes=%d", bytes);
            return ESP_FAIL;
        }
        return nvs_.write(key, data, bytes);
      default:
        ESP_LOGE(TAG, "Un support type.");
        return ESP_ERR_NOT_SUPPORTED;
    } 
}

/// @brief 保存一个用户数据
/// @param addr 用户数据地址
/// @return 返回索引，失败时返回 CONFIG_MAX_STORAGE
BitmapIndex StorageManager::Add(const void* addr)
{
    auto bitmap_index = GetFreeIndex();
    if (bitmap_index == CONFIG_MAX_STORAGE) {
        ESP_LOGE(TAG, "bitmap=%d, index=%d", bitmap_, bitmap_index);
        ESP_LOGE(TAG, "Can not save to nvs, storage is full.");
        return CONFIG_MAX_STORAGE;
    }

    esp_err_t err = ESP_OK;
    std::string pre = prefix_ + std::to_string(bitmap_index) + "-";
    std::string key;
    const uint8_t* offset;

    for(FieldCount field_index = 0; field_index < meta_.field_count; field_index++) {
        key = pre + std::to_string(field_index);
        offset = static_cast<const uint8_t*>(addr) + meta_.data[field_index].offset;

        err = WriteField(key, meta_.data[field_index].type, offset, meta_.data[field_index].bytes);
        if (ESP_OK != err) {
            ESP_LOGE(TAG, "Write to NVS failed, key=%s, err=%s", key.c_str(), esp_err_to_name(err));
            return CONFIG_MAX_STORAGE;
        }
    }
    bitmap_ |= IndexToBitmap(bitmap_index);
    err = nvs_.write(BITMAP_KEY, bitmap_);
    if (ESP_OK != err) {
        ESP_LOGE(TAG, "Save bitmap failed, err=%s", esp_err_to_name(err));
        return CONFIG_MAX_STORAGE;
    }
    used_ ++;
    return bitmap_index;
}

/// @brief 读取一个数据
/// @param index 数据的索引
/// @param addr 保存的地址
/// @return 读取成功返回ESP_OK
esp_err_t StorageManager::Read(const BitmapIndex index, void* addr)
{
    if (index >= CONFIG_MAX_STORAGE || !(bitmap_ & (BitmapType(1) << index))) {
        ESP_LOGE(TAG, "Invalid index: %zu, ignore it.", index);
        return ESP_ERR_INVALID_ARG;
    }

    esp_err_t err = ESP_OK;
    auto pre = prefix_ + std::to_string(index) + "-";
    std::string key;
    uint8_t* offset;

    for(FieldCount field_index = 0; field_index < meta_.field_count; field_index++) {
        key = pre + std::to_string(field_index);
        offset = reinterpret_cast<uint8_t*>(addr) + meta_.data[field_index].offset;

        err = ReadField(key, meta_.data[field_index].type, offset, meta_.data[field_index].bytes);
        if (ESP_OK != err) {
            ESP_LOGE(TAG, "Read field %d failed, err=%s", field_index, esp_err_to_name(err));
            return err;
        }
    }
    return err;
}

/// @brief 删除数据（消除其位图标志）
/// @param index 数据在位图中的索引
/// @return 写入结果
esp_err_t StorageManager::Del(const BitmapIndex index)
{
    auto mask = (BitmapType)1 << index;
    if ((index >= CONFIG_MAX_STORAGE) || (!(bitmap_ & mask))) {
        ESP_LOGE(TAG, "Invalid index: %zu, ignore it.", index);
        return ESP_ERR_INVALID_ARG;
    }

    bitmap_ &= ~mask;
    auto err = nvs_.write(BITMAP_KEY, bitmap_);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Del err, failed to save bitmap, err=%s", esp_err_to_name(err));
        return err;
    }
    used_ --;

    return err;
}

///
esp_err_t StorageManager::Del(const BitmapType mask)
{
    auto count = std::popcount(mask);
    if (used_ < count) {
        ESP_LOGE(TAG, "Del err, del something do not exit.");
        return ESP_ERR_INVALID_ARG;
    }

    bitmap_ &= ~mask;

    auto err = nvs_.write(BITMAP_KEY, bitmap_);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Del err, failed to save bitmap, err=%s", esp_err_to_name(err));
    } else {
        used_ -= count;
    }

    return err;
}

/// @brief 根据索引对比修改保存的数据
/// @param bitmap_index 修改索引
/// @param old_ptr 旧数据
/// @param new_ptr 新数据
/// @return 
esp_err_t StorageManager::DifferWrite(BitmapIndex bitmap_index, const void* old_ptr, const void* new_ptr)
{
    auto mask = (BitmapType)1 << bitmap_index;
    if ((bitmap_index >= CONFIG_MAX_STORAGE) || (!(bitmap_ & mask))) {
        ESP_LOGE(TAG, "Invalid index: %zu, ignore it.", bitmap_index);
        return ESP_ERR_INVALID_ARG;
    }

    std::string key;
    const uint8_t* odptr;
    const uint8_t* ndptr;
    esp_err_t err = ESP_OK;

    for (auto field_index = 0; field_index < meta_.field_count; field_index++) {
        odptr = static_cast<const uint8_t*>(old_ptr) + meta_.data[field_index].offset;
        ndptr = static_cast<const uint8_t*>(new_ptr) + meta_.data[field_index].offset;
        key = prefix_ + std::to_string(bitmap_index) + "-" + std::to_string(field_index);

        switch (meta_.data[field_index].type) {
          case kNormal_1:
            if (*ndptr != *odptr) {
                err = nvs_.write(key, *ndptr);
            }
            break;
          case kNormal_2:
            if (*reinterpret_cast<const uint16_t*>(ndptr) != *reinterpret_cast<const uint16_t*>(odptr)) {
                err = nvs_.write(key, *reinterpret_cast<const uint16_t*>(ndptr));
            }
            break;
          case kNormal_4:
            if (*reinterpret_cast<const uint32_t*>(ndptr) != *reinterpret_cast<const uint32_t*>(odptr)) {
                err = nvs_.write(key, *reinterpret_cast<const uint32_t*>(ndptr));
            }
            break;
          case kNormal_8:
            if (*reinterpret_cast<const uint64_t*>(ndptr) != *reinterpret_cast<const uint64_t*>(odptr)) {
                err = nvs_.write(key, *reinterpret_cast<const uint64_t*>(ndptr));
            }
            break;
          case kString:
            {
                const std::string& new_str = *reinterpret_cast<const std::string*>(ndptr);
                const std::string& old_str = *reinterpret_cast<const std::string*>(odptr);
                if ( new_str != old_str) {
                    err = nvs_.write(key, *reinterpret_cast<const std::string*>(ndptr));
                }
            }
            break;
          case kArray_Char:
            if(0 != strcmp(reinterpret_cast<const char*>(ndptr), reinterpret_cast<const char*>(odptr))) {
                err = nvs_.write(key, reinterpret_cast<const char*>(ndptr));
            }
            break;
          case kArray_Blob:
            {
                auto bytes = meta_.data[field_index].bytes;
                if (0 != memcmp(ndptr, odptr, bytes)) {
                    err = nvs_.write(key, static_cast<const void*>(ndptr), bytes);
                }
            }
            break;
          default:
            ESP_LOGE(TAG, "Unsupport type: %d.", meta_.data[field_index].bytes);
            return ESP_ERR_NOT_SUPPORTED;
        }
        if (ESP_OK != err) {
            ESP_LOGE(TAG, "Save differ data failed, filed index=%d.", field_index);
            break;
        }
    }

    return err;
}
